<?php

namespace App\Console\Commands;

use App\Models\Chapter;
use App\Models\Content;
use App\Http\Controllers\TestController;
use App\Models\Novel;
use App\Models\Volume;
use Illuminate\Console\Command;

class NovelSplit extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'novel:split {author?} {--no_shift} {--upload} ';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '分割小说';


    public $testController;

    /**
     * Create a new command instance.
     *
     *
     * NovelSplit constructor.
     * @param TestController $testController
     */
    public function __construct(TestController $testController)
    {
        parent::__construct();
        $this->testController = $testController;
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $upload   = $this->option('upload');
        $no_shift = $this->option('no_shift');
        $author   = $this->argument('author');

        $text_dir = storage_path('text');
        $handler  = opendir($text_dir);
        while(($filename = readdir($handler)) !== false) {
            if (in_array($filename, ['.', '..'])) {
                continue;
            }
            print $filename.PHP_EOL;
            $save_dir = storage_path('text_split').DIRECTORY_SEPARATOR.explode('_',explode('.',$filename)[0])[0];
            if(!is_dir($save_dir)){
                mkdir($save_dir);
            }
            $text_path = $text_dir.DIRECTORY_SEPARATOR.$filename;

            $contents=file_get_contents($text_path);
            $this->GB2UTF8($contents, $text_path);
            $this->chapter_split($text_path, $save_dir);
            if(!$no_shift){
                unlink($save_dir.DIRECTORY_SEPARATOR.'10000.txt');
            }
            if($upload){
                $this->upload(explode('_',explode('.',$filename)[0])[0], $author);
                copy($text_path,storage_path('text_split').DIRECTORY_SEPARATOR.$filename);
                unlink($text_path);
            }
            Chapter::whereRaw('LENGTH(abstract) < 4')->delete();
            Content::whereRaw('LENGTH(content) < 4')->delete();
        }
    }

    /**
     * 上传文件
     * @param $novel
     * @param $author
     * @return array
     */
    private function upload($novel, $author){
        $novel_check = Novel::where(['title'=>$novel])
            ->first();
        if($novel_check){
            return ['uploaded'];
        }
        $save_dir = storage_path('text_split').DIRECTORY_SEPARATOR.$novel;
        $handler = opendir($save_dir);
        $volume_num = 1;
        $chapter_name_len = 0;
        $novel = Novel::create(['title'=>$novel,
            'author'=>$author,
            'add_time'=>time(),
        ]);
        $volume = Volume::create(['volume_name'=>'卷'.$this->number2chinese($volume_num),
            'novel_id'=>$novel['id']]);
        while(($filename = readdir($handler)) !== false){
            if(in_array($filename,['.','..'])){
                continue;
            }
            $file = fopen($save_dir.DIRECTORY_SEPARATOR.$filename,'r');
            $chapter_name = '';
            $article = [];
            while(!feof($file)){
                $strings = fgets($file);
                $chapter_name = !$chapter_name?mb_substr($strings,0,50):$chapter_name;
                $article[] = $strings;
            }
            if($chapter_name_len<=mb_strlen($chapter_name)){
                $chapter_name_len = mb_strlen($chapter_name);
            } else{
                $chapter_name_len = 0;
                $volume_num++;
                $volume = Volume::create(['volume_name'=>'卷'.$this->number2chinese($volume_num),
                    'novel_id'=>$novel['id']]);
            }

            $article = implode($article);
            $abstract = trim(str_replace($chapter_name,'',mb_substr($article, 0, 50))).'...';
            $chapter = Chapter::create([
                'chapter_name'=>$chapter_name,
                'abstract'=>$abstract,
                'novel_id'=>$novel['id'],
                'volume_id'=>$volume['id'],
            ]);
            Content::create([
                'novel_id'=>$novel['id'],
                'chapter_id'=>$chapter['id'],
                'volume_id'=>$volume['id'],
                'content'=>$article,
            ]);

            print $filename;
        }
        closedir($handler);
    }

    /**
     * gb2312 转 utf8
     * @param $contents
     * @param $text_path
     */
    private function GB2UTF8($contents, $text_path){
        $charset[1]=substr($contents,0,1);
        $charset[2]=substr($contents,1,1);
        $charset[3]=substr($contents,2,1);
        if(ord($charset[1])==239&&ord($charset[2])==187&&ord($charset[3])==191){
            $rest=substr($contents,3);
//            $rest = mb_convert_encoding($rest, 'UTF-8', 'GB2312');
            $this->rewrite($text_path,$rest);
            print 'wipe of BOM';
        }else{
            $this->rewrite($text_path,$contents);
        }
    }

    /**
     * 分割章节
     * @param $text_path
     * @param $save_dir
     */
    private function chapter_split($text_path, $save_dir){
        $file = fopen($text_path,'r');
        $content = [];
        $chapter = 10000;
        for($i=0;!feof($file);$i++){
            $strings = fgets($file);
            $flag = preg_match('/^第.{1,10}[章回节]/', $strings) && mb_strlen($strings)<33;
            if($flag){
                print $strings;
                $save_path = $save_dir.DIRECTORY_SEPARATOR.$chapter.'.txt';
                file_put_contents($save_path, implode($content));
                $chapter++;
                $content = [$strings];
            }else{
                $content[] = $strings;
            }
        }
        $save_path = $save_dir.DIRECTORY_SEPARATOR.$chapter.'.txt';
        file_put_contents($save_path, implode($content));
        fclose($file);
    }

    /**
     * 转好格式，重新写入文件
     * @param $filename
     * @param $data
     */
    private function rewrite($filename,$data){
        $filenum=fopen($filename,'w');
        flock($filenum,LOCK_EX);
        fwrite($filenum,$data);
        fclose($filenum);
    }

    /**
     * 数字转中文
     * @param $number
     * @param bool $isRmb
     * @return string
     * @throws \Exception
     */
    private function number2chinese($number, $isRmb = false)
    {
        // 判断正确数字
        if (!preg_match('/^-?\d+(\.\d+)?$/', $number)) {
            throw new \Exception('number2chinese() wrong number', 1);
        }
        list($integer, $decimal) = explode('.', $number . '.0');

        // 检测是否为负数
        $symbol = '';
        if (substr($integer, 0, 1) == '-') {
            $symbol = '负';
            $integer = substr($integer, 1);
        }
        if (preg_match('/^-?\d+$/', $number)) {
            $decimal = null;
        }
        $integer = ltrim($integer, '0');

        // 准备参数
        $numArr = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九', '.' => '点'];
        $descArr = ['', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '万亿', '十', '百', '千', '兆', '十', '百', '千'];
        if ($isRmb) {
            $number = substr(sprintf("%.5f", $number), 0, -1);
            $numArr = ['', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖', '.' => '点'];
            $descArr = ['', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟', '万亿', '拾', '佰', '仟', '兆', '拾', '佰', '仟'];
            $rmbDescArr = ['角', '分', '厘', '毫'];
        }

        // 整数部分拼接
        $integerRes = '';
        $count = strlen($integer);
        if ($count > max(array_keys($descArr))) {
            throw new \Exception('number2chinese() number too large.', 1);
        } else if ($count == 0) {
            $integerRes = '零';
        } else {
            for ($i = 0; $i < $count; $i++) {
                $n = $integer[$i];      // 位上的数
                $j = $count - $i - 1;   // 单位数组 $descArr 的第几位
                // 零零的读法
                $isLing = $i > 1                    // 去除首位
                    && $n !== '0'                   // 本位数字不是零
                    && $integer[$i - 1] === '0';    // 上一位是零
                $cnZero = $isLing ? '零' : '';
                $cnNum = $numArr[$n];
                // 单位读法
                $isEmptyDanwei = ($n == '0' && $j % 4 != 0)     // 是零且一断位上
                    || substr($integer, $i - 3, 4) === '0000';  // 四个连续0
                $descMark = isset($cnDesc) ? $cnDesc : '';
                $cnDesc = $isEmptyDanwei ? '' : $descArr[$j];
                // 第一位是一十
                if ($i == 0 && $cnNum == '一' && $cnDesc == '十') $cnNum = '';
                // 二两的读法
                $isChangeEr = $n > 1 && $cnNum == '二'       // 去除首位
                    && !in_array($cnDesc, ['', '十', '百'])  // 不读两\两十\两百
                    && $descMark !== '十';                   // 不读十两
                if ($isChangeEr) $cnNum = '两';
                $integerRes .= $cnZero . $cnNum . $cnDesc;
            }
        }

        // 小数部分拼接
        $decimalRes = '';
        $count = strlen($decimal);
        if ($decimal === null) {
            $decimalRes = $isRmb ? '整' : '';
        } else if ($decimal === '0') {
            $decimalRes = '零';
        } else if ($count > max(array_keys($descArr))) {
            throw new \Exception('number2chinese() number too large.', 1);
        } else {
            for ($i = 0; $i < $count; $i++) {
                if ($isRmb && $i > count($rmbDescArr) - 1) break;
                $n = $decimal[$i];
                $cnZero = $n === '0' ? '零' : '';
                $cnNum = $numArr[$n];
                $cnDesc = $isRmb ? $rmbDescArr[$i] : '';
                $decimalRes .= $cnZero . $cnNum . $cnDesc;
            }
        }
        // 拼接结果
        $res = $symbol . ($isRmb ?
                $integerRes . ($decimalRes === '零' ? '元整' : "元$decimalRes") :
                $integerRes . ($decimalRes === '' ? '' : "点$decimalRes"));
        return $res;
    }

}
